package funcs

import (
	"app/pkg/config"
	"app/pkg/uuid"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"image"
	"math/rand"
	"os"
	"reflect"
	"strconv"
	"strings"
	"time"

	_ "image/gif"
	_ "image/jpeg"
	"image/png"
	_ "image/png"

	"github.com/dgrijalva/jwt-go"
	"github.com/jinzhu/copier"
	"github.com/nfnt/resize"
	"golang.org/x/exp/slices"
)

func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func GenerateSaltCode() string {
	t := time.Now()
	nowTimeStr := t.Format("060102")
	return strconv.Itoa(1) + nowTimeStr + strconv.FormatInt(int64(uuid.NewGoogleUUID().Id()), 10)
}

func IsNum(s string) bool {
	_, err := strconv.ParseFloat(s, 64)
	return err == nil
}

func CopyStructFields(toValue interface{}, fromValue interface{}) (err error) {
	return copier.Copy(toValue, fromValue)
}

// 转png
// filepath 完整文件路径
func ImageToPng(file *os.File, filepath string) error {
	targetFile, err := os.Create(filepath)
	if err != nil {
		return err
	}
	defer func() { targetFile.Close() }()
	img, _, err := image.Decode(file)
	if err != nil {
		return err
	}
	err = png.Encode(targetFile, img)
	if err != nil {
		return err
	}
	return nil
}

func PngImageCompress(file *os.File, compressFilepath string, width, height uint) error {
	img, _, err := image.Decode(file)
	if err != nil {
		return err
	}
	// resize to width 1000 using Lanczos resampling
	// and preserve aspect ratio
	m := resize.Resize(width, height, img, resize.Lanczos3)
	out, err := os.Create(compressFilepath)
	if err != nil {
		return err
	}
	defer out.Close()
	png.Encode(out, m)
	return nil
}

// 按照长度分割字符串
func ChunkString(s string, chunkSize int) []string {
	var chunks []string
	runes := []rune(s)

	if len(runes) == 0 {
		return []string{s}
	}

	for i := 0; i < len(runes); i += chunkSize {
		nn := i + chunkSize
		if nn > len(runes) {
			nn = len(runes)
		}
		chunks = append(chunks, string(runes[i:nn]))
	}
	return chunks
}

// 生成随机字符串
func GenRandomString(size int) string {
	const letterBytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
	arr := make([]byte, size)
	rand.Seed(time.Now().UnixNano()) //设置随机种子，不设置则默认Seed(1)
	for i := range arr {
		arr[i] = letterBytes[rand.Int63n(int64(len(letterBytes)))]
	}
	return string(arr)
}

// 生成随机slice int
func GenRandomInt(size int) []int {
	const letterBytes = "0123456789"
	arr := make([]int, size)
	rand.Seed(time.Now().UnixNano()) //设置随机种子，不设置则默认Seed(1)
	for i := range arr {
		arr[i], _ = strconv.Atoi(string(letterBytes[rand.Int63n(int64(len(letterBytes)))]))
	}
	return arr
}

func RandSlice[T any](slice []T) []T { //切片乱序
	if len(slice) < 2 {
		return slice
	}
	swap := reflect.Swapper(slice)
	rand.Seed(time.Now().Unix())
	for i := len(slice) - 1; i >= 0; i-- {
		j := rand.Intn(len(slice))
		swap(i, j)
	}
	return slice
}

// value 是否被包含于target中
func Contains(value interface{}, target interface{}) bool {
	targetValue := reflect.ValueOf(target)
	switch reflect.TypeOf(target).Kind() {
	case reflect.Slice, reflect.Array:
		for i := 0; i < targetValue.Len(); i++ {
			if targetValue.Index(i).Interface() == value {
				return true
			}
		}
	case reflect.Map:
		if targetValue.MapIndex(reflect.ValueOf(value)).IsValid() {
			return true
		}
	}
	return false
}

// hash sha256
func Sha256(str string) string {
	h := sha256.New()
	h.Write([]byte(str))
	return fmt.Sprintf("%x", h.Sum(nil))
}

// 登录密码加密
func EncryptLoginPass(pass, salt string) string {
	return Sha256(fmt.Sprintf("%s,%s", salt, pass))
}

// slice 帮助函数 开始

func FindIndexOfSlice[T comparable](sli []T, e T) int {
	return slices.IndexFunc(sli, func(i T) bool {
		return i == e
	})
}

var seeds = []string{"o", "q", "g", "a", "c", "e", "i", "s", "k", "m"} //"oqgaceiskm"

func IdEncode(id int64) string {
	var encodeSlice []string
	s := strconv.FormatInt(int64(id), 10)
	sli := strings.Split(s, "")
	for _, v := range sli {
		index, _ := strconv.Atoi(v)
		if index == 0 {
			index = 10
		}
		encodeSlice = append(encodeSlice, seeds[index-1])
	}
	return strings.Join(encodeSlice, "")
}

func IdDecode(s string) int64 {
	resultSli := make([]string, 10)
	sli := strings.Split(s, "")
	for _, v := range sli {
		for index, seed := range seeds {
			if seed == v {
				rstIndex := index + 1
				if rstIndex == 10 {
					rstIndex = 0
				}
				resultSli = append(resultSli, strconv.Itoa(rstIndex))
			}
		}
	}
	id, _ := strconv.ParseInt(strings.Join(resultSli, ""), 10, 64)
	return id
}

func SHA1(s string) string {

	o := sha1.New()

	o.Write([]byte(s))

	return hex.EncodeToString(o.Sum(nil))

}

// slice 帮助函数 结束

func JwtEncrypt(uid int64, sign string) (string, error) {
	if sign == "" {
		sign = config.Config.App.JwtSignKey
	}
	//生成jwt sign
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"uid": uid,
		"exp": time.Now().AddDate(0, 0, config.Config.App.JwtSignTTL).Unix(), //过期时间
		"nbf": time.Now().Unix(),                                             //生效时间
		"iat": time.Now().Unix(),                                             //签名时间
		"aud": "mddapi",                                                      //适用人群
	})
	return token.SignedString([]byte(sign))
}
